﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Diagnostics;

namespace RangeScrollControls
{
	public partial class RangeScrollBar : UserControl
	{
		public RangeScrollBar()
		{
			// Required to initialize variables
			InitializeComponent();
			UpdateAppearance();
			LimitRangeValue = true;
		}

		private int min = 0;
		private int max = 100;
		protected int leftValue = 0;
		protected int rightValue = 100;

		public Brush Background
		{
			get
			{
				return LayoutRoot.Background;
			}
			set
			{
				LayoutRoot.Background = value;
			}
		}

		public Brush TrackBrush
		{
			get
			{
				return slideChannel.Stroke;
			}

			set
			{
				slideChannel.Fill = slideChannel.Stroke = value;
			}
		}

		public Brush SliderBrush
		{
			get
			{
				return leftSlider.Stroke;
			}
			set
			{
				leftSlider.Fill = leftSlider.Stroke = rightSlider.Fill = rightSlider.Stroke = rangeBar.Fill = rangeBar.Stroke = value;
			}
		}

		public int Min 
		{ 
			get { return min; } 
			set 
			{
				min = value;
				UpdateAppearance();
			}
		}
		public int Max
		{
			get { return max; }
			set
			{
				max = value;
				UpdateAppearance();
			}
		}
		public virtual int LeftValue
		{
			get
			{
				return leftValue;
			}
			set
			{
				if (leftValue != value)
				{
					leftValue = value;
					OnValueChanged();
					UpdateAppearance();
				}
			}
		}
		public virtual int RightValue
		{
			get
			{
				return rightValue;
			}
			set
			{
				if (rightValue != value)
				{
					rightValue = value;
					OnValueChanged();
					UpdateAppearance();
				}
			}
		}
		public event EventHandler ValueChanged;

		protected virtual void OnValueChanged()
		{
			if (ValueChanged != null)
				ValueChanged(this, new EventArgs());
		}

		private void UpdateAppearance()
		{
			double range = RangeSize();
			if (range == 0)
				return;

			double leftPosition = CalcAbsolutePosition((leftValue - min)/range);
			double rightPosition = CalcAbsolutePosition((rightValue - min) / range);
			leftSlider.Margin = new Thickness(leftPosition, 0.0, 0.0, 0.0);
			rightSlider.Margin = new Thickness(rightPosition, 0.0, 0.0, 0.0);
			rangeBar.Margin = new Thickness(leftPosition + Height/2, rangeBar.Margin.Top, rangeBar.Margin.Right, rangeBar.Margin.Bottom);
			rangeBar.Width = (rightPosition - leftPosition);
		}

		private double RangeSize()
		{
			double range = max - min;
			return range;
		}

		private double CalcAbsolutePosition(double p)
		{
			double innerSize = Width - Height;
			return p * innerSize;
		}

		public int mouseTarget = -1; // -1 == none, 0 = left, 1 = right, 2 = rangebar
		public double mouseDownPosition = 0.0;
		private int oldValue;
		private void leftSlider_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
		{
			mouseTarget = 0;
			oldValue = leftValue;
			mouseDownPosition = e.GetPosition(this).X;
			leftSlider.CaptureMouse();
		}

		private void rightSlider_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
		{
			mouseTarget = 1;
			oldValue = rightValue;
			mouseDownPosition = e.GetPosition(this).X;
			rightSlider.CaptureMouse();
		}

		private void rangeBar_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
		{
			mouseTarget = 2;
			oldValue = leftValue;
			mouseDownPosition = e.GetPosition(this).X;
			rangeBar.CaptureMouse();
		}

		private void subcontrol_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
		{
			mouseTarget = -1;
			leftSlider.ReleaseMouseCapture();
			rightSlider.ReleaseMouseCapture();
			rangeBar.ReleaseMouseCapture();
		}

		private void rangeBar_MouseMove(object sender, MouseEventArgs e)
		{
			if (mouseTarget == 2)
			{
				var delta = (e.GetPosition(this).X - mouseDownPosition) / (Width - Height) * RangeSize();
				if (delta < min-oldValue)
					delta = min-oldValue;
				var range = rightValue - leftValue;
				var oldRight = oldValue + range;
				if (delta > max - oldRight)
					delta = max - oldRight;
				
				leftValue = oldValue + (int)delta;
				RightValue = leftValue + range;
			}
		}

		protected bool LimitRangeValue
		{
			get;
			set;
		}

		private void leftSlider_MouseMove(object sender, MouseEventArgs e)
		{
			if (mouseTarget == 0)
			{
				if (!LimitRangeValue)
				{
					LeftValue = (int)Math.Min(Math.Max(min, GetSliderPositionAtMouseMove(e)), max);
				}
				else
				{
					LeftValue = (int)Math.Min(Math.Max(min, GetSliderPositionAtMouseMove(e)), rightValue);
				}
			}
		}

		private double GetSliderPositionAtMouseMove(MouseEventArgs e)
		{
			var curPos = e.GetPosition(this).X;
			var delta = curPos - mouseDownPosition;
			var newValue = oldValue + delta / (Width - Height) * RangeSize();
			return newValue;
		}

		private void rightSlider_MouseMove(object sender, MouseEventArgs e)
		{
			if (mouseTarget == 1)
			{
				RightValue = (int)Math.Min(Math.Max(leftValue, GetSliderPositionAtMouseMove(e)), max);
			}
		}

		protected void UserControl_SizeChanged(object sender, SizeChangedEventArgs e)
		{
			slideChannel.X1 = Height / 2;
			slideChannel.X2 = Width - Height / 2;
			UpdateAppearance();
		}

		private void rightSlider_MouseEnter(object sender, MouseEventArgs e)
		{
			rightSlider.Cursor = Cursors.Hand;

			System.Windows.Media.Effects.DropShadowEffect ds = new System.Windows.Media.Effects.DropShadowEffect();
			ds.Color = Colors.Gray;
			ds.BlurRadius = 5;
			ds.ShadowDepth = 0;
			rightSlider.Effect = ds;
		}

		private void rightSlider_MouseLeave(object sender, MouseEventArgs e)
		{
			rightSlider.Cursor = Cursors.Arrow;
			rightSlider.Effect = null;
		}

		private void leftSlider_MouseEnter(object sender, MouseEventArgs e)
		{
			leftSlider.Cursor = Cursors.Hand;

			System.Windows.Media.Effects.DropShadowEffect ds = new System.Windows.Media.Effects.DropShadowEffect();
			ds.Color = Colors.Gray;
			ds.BlurRadius = 5;
			ds.ShadowDepth = 0;
			leftSlider.Effect = ds;
		}

		private void leftSlider_MouseLeave(object sender, MouseEventArgs e)
		{
			leftSlider.Cursor = Cursors.Arrow;
			leftSlider.Effect = null;
		}

		private void rangeBar_MouseEnter(object sender, MouseEventArgs e)
		{
			rangeBar.Cursor = Cursors.Hand;

			System.Windows.Media.Effects.DropShadowEffect ds = new System.Windows.Media.Effects.DropShadowEffect();
			ds.Color = Colors.Gray;
			ds.BlurRadius = 5;
			ds.ShadowDepth = 0;
			rangeBar.Effect = ds;
		}

		private void rangeBar_MouseLeave(object sender, MouseEventArgs e)
		{
			rangeBar.Cursor = Cursors.Arrow;
			rangeBar.Effect = null;
		}

		public void HideRight()
		{
			rightSlider.Visibility = System.Windows.Visibility.Collapsed;
			LimitRangeValue = false;
		}
	}
}